// 
// Copyright (c) 2013 Jason Bell
// 
// Permission is hereby granted, free of charge, to any person obtaining a 
// copy of this software and associated documentation files (the "Software"), 
// to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the 
// Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included 
// in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
// 

using System;
using System.Runtime.InteropServices;

namespace Gharen.GLCore.X11
{
	public class X
	{
		private static readonly object Lock = new object();
		
		[DllImport("libX11", EntryPoint = "XOpenDisplay")]
        extern static IntPtr sys_XOpenDisplay(IntPtr display);
        public static IntPtr OpenDisplay(IntPtr display)
        {
            lock (Lock)
            {
                return sys_XOpenDisplay(display);
            }
        }
		
		[DllImport("libX11", EntryPoint = "XDefaultScreen")]
        public extern static int DefaultScreen(IntPtr display);
		
		[DllImport("libX11", EntryPoint = "XFree")]
        public extern static int Free(IntPtr data);
		
		[DllImport("libX11", EntryPoint = "XCreateColormap")]
        public static extern IntPtr CreateColormap(IntPtr display, IntPtr window, IntPtr visual, int alloc);
		
		[DllImport("libX11", EntryPoint = "XRootWindow")]
        public extern static IntPtr RootWindow(IntPtr display, int screen_number);
		
		[DllImport("libX11", EntryPoint = "XCreateWindow")]
        [CLSCompliant(false)]
        public extern static IntPtr CreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes);
	
		[DllImport("libX11", EntryPoint = "XStoreName")]
        public extern static int StoreName(IntPtr display, IntPtr window, string window_name);
		
		[DllImport("libX11", EntryPoint = "XMapWindow")]
        public extern static int MapWindow(IntPtr display, IntPtr window);
		
		[DllImport("libX11", EntryPoint = "XFetchName")]
        public extern static int FetchName(IntPtr display, IntPtr window, ref IntPtr window_name);

        [DllImport("libX11", EntryPoint = "XQueryExtension")]
        public extern static int QueryExtension(IntPtr display, string extension_name, out int major, out int first_event, out int first_error);

        [DllImport("libc", SetLastError = false)]
        public static extern IntPtr memcpy(IntPtr dest, IntPtr src, int count);

        const string XrandrLibrary = "libXrandr.so.2";

        [DllImport(XrandrLibrary)]
        public static extern IntPtr XRRGetScreenInfo(IntPtr dpy, IntPtr draw);

        [DllImport(XrandrLibrary)]
        public static extern IntPtr XRRConfigSizes(IntPtr config, out int nsizes);

        [DllImport("libX11")]
        unsafe static extern int* XListDepths(IntPtr display, int screen_number, int* count_return);
		
		[DllImport("libX11")]
        internal extern static bool XCheckIfEvent(IntPtr display, ref XEvent e, IntPtr predicate, IntPtr arg );
		
		[DllImport("libX11", EntryPoint = "XMaskEvent")]
        extern internal static void MaskEvent(IntPtr display, EventMask event_mask, ref XEvent e);
		
		        [DllImport("libX11", EntryPoint = "XCheckMaskEvent")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool CheckMaskEvent(IntPtr display, EventMask event_mask, ref XEvent event_return);
		
		        [DllImport("libX11", EntryPoint = "XFlush")]
        public extern static int Flush(IntPtr display);

                [DllImport("libX11")]
                public static extern int XKeycodeToKeysym(IntPtr display, byte keycode, int index);

                [DllImport("libX11", EntryPoint = "XDisplayKeycodes")]
                public static extern void DisplayKeycodes(IntPtr display, ref int min_keycodes_return, ref int max_keycodes_return);

                [DllImport("libX11", EntryPoint = "XInternAtom")]
                public extern static IntPtr InternAtom(IntPtr display, string atom_name, bool only_if_exists);

                [DllImport("libX11", EntryPoint = "XSetWMProtocols")]
                public extern static int SetWMProtocols(IntPtr display, IntPtr window, IntPtr[] atom, int count);

                [DllImport("libX11", EntryPoint = "XNextEvent")]
                internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);

                [DllImport("libX11")]
                public extern static int XPending(IntPtr diplay);

                [DllImport("libX11", EntryPoint = "XDestroyWindow")]
                public extern static int DestroyWindow(IntPtr display, IntPtr window);

                [DllImport("libX11", EntryPoint = "XCloseDisplay")]
                public extern static int CloseDisplay(IntPtr display);

        public static int[] ListDepths(IntPtr display, int screen_number)
        {
            unsafe
            {
                int count;
                int* data = XListDepths(display, screen_number, &count);
                if (count == 0)
                    return null;
                int[] depths = new int[count];
                for (int i = 0; i < count; i++)
                    depths[i] = *(data + i);

                return depths;
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct XRRScreenSize
    {
        internal int Width, Height;
        internal int MWidth, MHeight;
    };
	
	[StructLayout(LayoutKind.Sequential)]
    public struct XSetWindowAttributes
    {
        public IntPtr background_pixmap;
        public IntPtr background_pixel;
        public IntPtr border_pixmap;
        public IntPtr border_pixel;
        public Gravity bit_gravity;
        public Gravity win_gravity;
        public int backing_store;
        public IntPtr backing_planes;
        public IntPtr backing_pixel;
        public bool save_under;
        public IntPtr event_mask;
        public IntPtr do_not_propagate_mask;
        public bool override_redirect;
        public IntPtr colormap;
        public IntPtr cursor;
    }
	
	public enum Gravity
    {
        ForgetGravity = 0,
        NorthWestGravity = 1,
        NorthGravity = 2,
        NorthEastGravity = 3,
        WestGravity = 4,
        CenterGravity = 5,
        EastGravity = 6,
        SouthWestGravity = 7,
        SouthGravity = 8,
        SouthEastGravity = 9,
        StaticGravity = 10
    }
	
	[StructLayout(LayoutKind.Sequential)]
    public struct XVisualInfo
    {
        public IntPtr Visual;
        public IntPtr VisualID;
        public int Screen;
        public int Depth;
        public XVisualClass Class;
        public long RedMask;
        public long GreenMask;
        public long blueMask;
        public int ColormapSize;
        public int BitsPerRgb;

        public override string ToString()
        {
            return String.Format("id ({0}), screen ({1}), depth ({2}), class ({3})",
                VisualID, Screen, Depth, Class);
        }
    }
	
	internal enum XEventName
    {
        KeyPress = 2,
        KeyRelease = 3,
        ButtonPress = 4,
        ButtonRelease = 5,
        MotionNotify = 6,
        EnterNotify = 7,
        LeaveNotify = 8,
        FocusIn = 9,
        FocusOut = 10,
        KeymapNotify = 11,
        Expose = 12,
        GraphicsExpose = 13,
        NoExpose = 14,
        VisibilityNotify = 15,
        CreateNotify = 16,
        DestroyNotify = 17,
        UnmapNotify = 18,
        MapNotify = 19,
        MapRequest = 20,
        ReparentNotify = 21,
        ConfigureNotify = 22,
        ConfigureRequest = 23,
        GravityNotify = 24,
        ResizeRequest = 25,
        CirculateNotify = 26,
        CirculateRequest = 27,
        PropertyNotify = 28,
        SelectionClear = 29,
        SelectionRequest = 30,
        SelectionNotify = 31,
        ColormapNotify = 32,
        ClientMessage = 33,
        MappingNotify = 34,
        GenericEvent = 35,

        LASTEvent
    }
	
	    internal enum NotifyMode
    {
        NotifyNormal = 0,
        NotifyGrab = 1,
        NotifyUngrab = 2
    }

    internal enum NotifyDetail
    {
        NotifyAncestor = 0,
        NotifyVirtual = 1,
        NotifyInferior = 2,
        NotifyNonlinear = 3,
        NotifyNonlinearVirtual = 4,
        NotifyPointer = 5,
        NotifyPointerRoot = 6,
        NotifyDetailNone = 7
    }
	
	 internal enum XRequest : byte
    {
        X_CreateWindow = 1,
        X_ChangeWindowAttributes = 2,
        X_GetWindowAttributes = 3,
        X_DestroyWindow = 4,
        X_DestroySubwindows = 5,
        X_ChangeSaveSet = 6,
        X_ReparentWindow = 7,
        X_MapWindow = 8,
        X_MapSubwindows = 9,
        X_UnmapWindow = 10,
        X_UnmapSubwindows = 11,
        X_ConfigureWindow = 12,
        X_CirculateWindow = 13,
        X_GetGeometry = 14,
        X_QueryTree = 15,
        X_InternAtom = 16,
        X_GetAtomName = 17,
        X_ChangeProperty = 18,
        X_DeleteProperty = 19,
        X_GetProperty = 20,
        X_ListProperties = 21,
        X_SetSelectionOwner = 22,
        X_GetSelectionOwner = 23,
        X_ConvertSelection = 24,
        X_SendEvent = 25,
        X_GrabPointer = 26,
        X_UngrabPointer = 27,
        X_GrabButton = 28,
        X_UngrabButton = 29,
        X_ChangeActivePointerGrab = 30,
        X_GrabKeyboard = 31,
        X_UngrabKeyboard = 32,
        X_GrabKey = 33,
        X_UngrabKey = 34,
        X_AllowEvents = 35,
        X_GrabServer = 36,
        X_UngrabServer = 37,
        X_QueryPointer = 38,
        X_GetMotionEvents = 39,
        X_TranslateCoords = 40,
        X_WarpPointer = 41,
        X_SetInputFocus = 42,
        X_GetInputFocus = 43,
        X_QueryKeymap = 44,
        X_OpenFont = 45,
        X_CloseFont = 46,
        X_QueryFont = 47,
        X_QueryTextExtents = 48,
        X_ListFonts = 49,
        X_ListFontsWithInfo = 50,
        X_SetFontPath = 51,
        X_GetFontPath = 52,
        X_CreatePixmap = 53,
        X_FreePixmap = 54,
        X_CreateGC = 55,
        X_ChangeGC = 56,
        X_CopyGC = 57,
        X_SetDashes = 58,
        X_SetClipRectangles = 59,
        X_FreeGC = 60,
        X_ClearArea = 61,
        X_CopyArea = 62,
        X_CopyPlane = 63,
        X_PolyPoint = 64,
        X_PolyLine = 65,
        X_PolySegment = 66,
        X_PolyRectangle = 67,
        X_PolyArc = 68,
        X_FillPoly = 69,
        X_PolyFillRectangle = 70,
        X_PolyFillArc = 71,
        X_PutImage = 72,
        X_GetImage = 73,
        X_PolyText8 = 74,
        X_PolyText16 = 75,
        X_ImageText8 = 76,
        X_ImageText16 = 77,
        X_CreateColormap = 78,
        X_FreeColormap = 79,
        X_CopyColormapAndFree = 80,
        X_InstallColormap = 81,
        X_UninstallColormap = 82,
        X_ListInstalledColormaps = 83,
        X_AllocColor = 84,
        X_AllocNamedColor = 85,
        X_AllocColorCells = 86,
        X_AllocColorPlanes = 87,
        X_FreeColors = 88,
        X_StoreColors = 89,
        X_StoreNamedColor = 90,
        X_QueryColors = 91,
        X_LookupColor = 92,
        X_CreateCursor = 93,
        X_CreateGlyphCursor = 94,
        X_FreeCursor = 95,
        X_RecolorCursor = 96,
        X_QueryBestSize = 97,
        X_QueryExtension = 98,
        X_ListExtensions = 99,
        X_ChangeKeyboardMapping = 100,
        X_GetKeyboardMapping = 101,
        X_ChangeKeyboardControl = 102,
        X_GetKeyboardControl = 103,
        X_Bell = 104,
        X_ChangePointerControl = 105,
        X_GetPointerControl = 106,
        X_SetScreenSaver = 107,
        X_GetScreenSaver = 108,
        X_ChangeHosts = 109,
        X_ListHosts = 110,
        X_SetAccessControl = 111,
        X_SetCloseDownMode = 112,
        X_KillClient = 113,
        X_RotateProperties = 114,
        X_ForceScreenSaver = 115,
        X_SetPointerMapping = 116,
        X_GetPointerMapping = 117,
        X_SetModifierMapping = 118,
        X_GetModifierMapping = 119,
        X_NoOperation = 127
    }
	
	[StructLayout(LayoutKind.Explicit)]
    internal struct XEvent
    {
        [FieldOffset(0)]
        public XEventName type;
        [FieldOffset(0)]
        public XAnyEvent AnyEvent;
        [FieldOffset(0)]
        public XKeyEvent KeyEvent;
        [FieldOffset(0)]
        public XButtonEvent ButtonEvent;
        [FieldOffset(0)]
        public XMotionEvent MotionEvent;
        [FieldOffset(0)]
        public XCrossingEvent CrossingEvent;
        [FieldOffset(0)]
        public XFocusChangeEvent FocusChangeEvent;
        [FieldOffset(0)]
        public XExposeEvent ExposeEvent;
        [FieldOffset(0)]
        public XGraphicsExposeEvent GraphicsExposeEvent;
        [FieldOffset(0)]
        public XNoExposeEvent NoExposeEvent;
        [FieldOffset(0)]
        public XVisibilityEvent VisibilityEvent;
        [FieldOffset(0)]
        public XCreateWindowEvent CreateWindowEvent;
        [FieldOffset(0)]
        public XDestroyWindowEvent DestroyWindowEvent;
        [FieldOffset(0)]
        public XUnmapEvent UnmapEvent;
        [FieldOffset(0)]
        public XMapEvent MapEvent;
        [FieldOffset(0)]
        public XMapRequestEvent MapRequestEvent;
        [FieldOffset(0)]
        public XReparentEvent ReparentEvent;
        [FieldOffset(0)]
        public XConfigureEvent ConfigureEvent;
        [FieldOffset(0)]
        public XGravityEvent GravityEvent;
        [FieldOffset(0)]
        public XResizeRequestEvent ResizeRequestEvent;
        [FieldOffset(0)]
        public XConfigureRequestEvent ConfigureRequestEvent;
        [FieldOffset(0)]
        public XCirculateEvent CirculateEvent;
        [FieldOffset(0)]
        public XCirculateRequestEvent CirculateRequestEvent;
        [FieldOffset(0)]
        public XPropertyEvent PropertyEvent;
        [FieldOffset(0)]
        public XSelectionClearEvent SelectionClearEvent;
        [FieldOffset(0)]
        public XSelectionRequestEvent SelectionRequestEvent;
        [FieldOffset(0)]
        public XSelectionEvent SelectionEvent;
        [FieldOffset(0)]
        public XColormapEvent ColormapEvent;
        [FieldOffset(0)]
        public XClientMessageEvent ClientMessageEvent;
        [FieldOffset(0)]
        public XMappingEvent MappingEvent;
        [FieldOffset(0)]
        public XErrorEvent ErrorEvent;
        [FieldOffset(0)]
        public XKeymapEvent KeymapEvent;
        [FieldOffset(0)]
        public XGenericEvent GenericEvent;
        [FieldOffset(0)]
        public XGenericEventCookie GenericEventCookie;

        //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=24)]
        //[ FieldOffset(0) ] public int[] pad;
        [FieldOffset(0)]
        public XEventPad Pad;
        public override string ToString()
        {
            switch (type)
            {
                case XEventName.PropertyNotify:
                    return ToString(PropertyEvent);
                case XEventName.ResizeRequest:
                    return ToString(ResizeRequestEvent);
                case XEventName.ConfigureNotify:
                    return ToString(ConfigureEvent);
                default:
                    return type.ToString();
            }
        }

        public static string ToString(object ev)
        {
            string result = string.Empty;
            Type type = ev.GetType();
            System.Reflection.FieldInfo[] fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance);
            for (int i = 0; i < fields.Length; i++)
            {
                if (result != string.Empty)
                {
                    result += ", ";
                }
                object value = fields[i].GetValue(ev);
                result += fields[i].Name + "=" + (value == null ? "<null>" : value.ToString());
            }
            return type.Name + " (" + result + ")";
        }
    }
	
	    [StructLayout(LayoutKind.Sequential)]
    internal struct XAnyEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XKeyEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr root;
        public IntPtr subwindow;
        public IntPtr time;
        public int x;
        public int y;
        public int x_root;
        public int y_root;
        public int state;
        public int keycode;
        public bool same_screen;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XButtonEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr root;
        public IntPtr subwindow;
        public IntPtr time;
        public int x;
        public int y;
        public int x_root;
        public int y_root;
        public int state;
        public int button;
        public bool same_screen;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XMotionEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr root;
        public IntPtr subwindow;
        public IntPtr time;
        public int x;
        public int y;
        public int x_root;
        public int y_root;
        public int state;
        public byte is_hint;
        public bool same_screen;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XCrossingEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr root;
        public IntPtr subwindow;
        public IntPtr time;
        public int x;
        public int y;
        public int x_root;
        public int y_root;
        public NotifyMode mode;
        public NotifyDetail detail;
        public bool same_screen;
        public bool focus;
        public int state;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XFocusChangeEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public int mode;
        public NotifyDetail detail;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XKeymapEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public byte key_vector0;
        public byte key_vector1;
        public byte key_vector2;
        public byte key_vector3;
        public byte key_vector4;
        public byte key_vector5;
        public byte key_vector6;
        public byte key_vector7;
        public byte key_vector8;
        public byte key_vector9;
        public byte key_vector10;
        public byte key_vector11;
        public byte key_vector12;
        public byte key_vector13;
        public byte key_vector14;
        public byte key_vector15;
        public byte key_vector16;
        public byte key_vector17;
        public byte key_vector18;
        public byte key_vector19;
        public byte key_vector20;
        public byte key_vector21;
        public byte key_vector22;
        public byte key_vector23;
        public byte key_vector24;
        public byte key_vector25;
        public byte key_vector26;
        public byte key_vector27;
        public byte key_vector28;
        public byte key_vector29;
        public byte key_vector30;
        public byte key_vector31;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XExposeEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public int x;
        public int y;
        public int width;
        public int height;
        public int count;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XGraphicsExposeEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr drawable;
        public int x;
        public int y;
        public int width;
        public int height;
        public int count;
        public int major_code;
        public int minor_code;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XNoExposeEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr drawable;
        public int major_code;
        public int minor_code;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XVisibilityEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public int state;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XCreateWindowEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr parent;
        public IntPtr window;
        public int x;
        public int y;
        public int width;
        public int height;
        public int border_width;
        public bool override_redirect;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XDestroyWindowEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr xevent;
        public IntPtr window;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XUnmapEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr xevent;
        public IntPtr window;
        public bool from_configure;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XMapEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr xevent;
        public IntPtr window;
        public bool override_redirect;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XMapRequestEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr parent;
        public IntPtr window;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XReparentEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr xevent;
        public IntPtr window;
        public IntPtr parent;
        public int x;
        public int y;
        public bool override_redirect;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XConfigureEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr xevent;
        public IntPtr window;
        public int x;
        public int y;
        public int width;
        public int height;
        public int border_width;
        public IntPtr above;
        public bool override_redirect;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XGravityEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr xevent;
        public IntPtr window;
        public int x;
        public int y;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XResizeRequestEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public int width;
        public int height;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XConfigureRequestEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr parent;
        public IntPtr window;
        public int x;
        public int y;
        public int width;
        public int height;
        public int border_width;
        public IntPtr above;
        public int detail;
        public IntPtr value_mask;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XCirculateEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr xevent;
        public IntPtr window;
        public int place;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XCirculateRequestEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr parent;
        public IntPtr window;
        public int place;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XPropertyEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr atom;
        public IntPtr time;
        public int state;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XSelectionClearEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr selection;
        public IntPtr time;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XSelectionRequestEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr owner;
        public IntPtr requestor;
        public IntPtr selection;
        public IntPtr target;
        public IntPtr property;
        public IntPtr time;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XSelectionEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr requestor;
        public IntPtr selection;
        public IntPtr target;
        public IntPtr property;
        public IntPtr time;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XColormapEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr colormap;
        public bool c_new;
        public int state;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XClientMessageEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public IntPtr message_type;
        public int format;
        public IntPtr ptr1;
        public IntPtr ptr2;
        public IntPtr ptr3;
        public IntPtr ptr4;
        public IntPtr ptr5;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XMappingEvent
    {
        public XEventName type;
        public IntPtr serial;
        public bool send_event;
        public IntPtr display;
        public IntPtr window;
        public int request;
        public int first_keycode;
        public int count;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XErrorEvent
    {
        public XEventName type;
        public IntPtr display;
        public IntPtr resourceid;
        public IntPtr serial;
        public byte error_code;
        public XRequest request_code;
        public byte minor_code;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XEventPad
    {
        public IntPtr pad0;
        public IntPtr pad1;
        public IntPtr pad2;
        public IntPtr pad3;
        public IntPtr pad4;
        public IntPtr pad5;
        public IntPtr pad6;
        public IntPtr pad7;
        public IntPtr pad8;
        public IntPtr pad9;
        public IntPtr pad10;
        public IntPtr pad11;
        public IntPtr pad12;
        public IntPtr pad13;
        public IntPtr pad14;
        public IntPtr pad15;
        public IntPtr pad16;
        public IntPtr pad17;
        public IntPtr pad18;
        public IntPtr pad19;
        public IntPtr pad20;
        public IntPtr pad21;
        public IntPtr pad22;
        public IntPtr pad23;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XGenericEvent
    {
        public int type;         // of event. Always GenericEvent
        public IntPtr serial;       // # of last request processed
        public bool send_event;   // true if from SendEvent request
        public IntPtr display;     // Display the event was read from
        public int extension;    // major opcode of extension that caused the event
        public int evtype;       // actual event type.
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct XGenericEventCookie
    {
        public int type;         // of event. Always GenericEvent
        public IntPtr serial;       // # of last request processed
        public bool send_event;   // true if from SendEvent request
        public IntPtr display;     // Display the event was read from
        public int extension;    // major opcode of extension that caused the event
        public int evtype;       // actual event type.
        public uint cookie;       // unique event cookie
        public IntPtr data;        // actual event data
    }

    //[CLSCompliant(false)]
    internal enum XKey
    {
        /*
         * TTY function keys, cleverly chosen to map to ASCII, for convenience of
         * programming, but could have been arbitrary (at the cost of lookup
         * tables in client code).
         */

        BackSpace = 0xff08,  /* Back space, back char */
        Tab = 0xff09,
        Linefeed = 0xff0a,  /* Linefeed, LF */
        Clear = 0xff0b,
        Return = 0xff0d,  /* Return, enter */
        Pause = 0xff13,  /* Pause, hold */
        Scroll_Lock = 0xff14,
        Sys_Req = 0xff15,
        Escape = 0xff1b,
        Delete = 0xffff,  /* Delete, rubout */



        /* International & multi-key character composition */

        Multi_key = 0xff20,  /* Multi-key character compose */
        Codeinput = 0xff37,
        SingleCandidate = 0xff3c,
        MultipleCandidate = 0xff3d,
        PreviousCandidate = 0xff3e,

        /* Japanese keyboard support */

        Kanji = 0xff21,  /* Kanji, Kanji convert */
        Muhenkan = 0xff22,  /* Cancel Conversion */
        Henkan_Mode = 0xff23,  /* Start/Stop Conversion */
        Henkan = 0xff23,  /* Alias for Henkan_Mode */
        Romaji = 0xff24,  /* to Romaji */
        Hiragana = 0xff25,  /* to Hiragana */
        Katakana = 0xff26,  /* to Katakana */
        Hiragana_Katakana = 0xff27,  /* Hiragana/Katakana toggle */
        Zenkaku = 0xff28,  /* to Zenkaku */
        Hankaku = 0xff29,  /* to Hankaku */
        Zenkaku_Hankaku = 0xff2a,  /* Zenkaku/Hankaku toggle */
        Touroku = 0xff2b,  /* Add to Dictionary */
        Massyo = 0xff2c,  /* Delete from Dictionary */
        Kana_Lock = 0xff2d,  /* Kana Lock */
        Kana_Shift = 0xff2e,  /* Kana Shift */
        Eisu_Shift = 0xff2f,  /* Alphanumeric Shift */
        Eisu_toggle = 0xff30,  /* Alphanumeric toggle */
        Kanji_Bangou = 0xff37,  /* Codeinput */
        Zen_Koho = 0xff3d,  /* Multiple/All Candidate(s) */
        Mae_Koho = 0xff3e,  /* Previous Candidate */

        /* 0xff31 thru 0xff3f are under XK_KOREAN */

        /* Cursor control & motion */

        Home = 0xff50,
        Left = 0xff51,  /* Move left, left arrow */
        Up = 0xff52,  /* Move up, up arrow */
        Right = 0xff53,  /* Move right, right arrow */
        Down = 0xff54,  /* Move down, down arrow */
        Prior = 0xff55,  /* Prior, previous */
        Page_Up = 0xff55,
        Next = 0xff56,  /* Next */
        Page_Down = 0xff56,
        End = 0xff57,  /* EOL */
        Begin = 0xff58,  /* BOL */


        /* Misc functions */

        Select = 0xff60,  /* Select, mark */
        Print = 0xff61,
        Execute = 0xff62,  /* Execute, run, do */
        Insert = 0xff63,  /* Insert, insert here */
        Undo = 0xff65,
        Redo = 0xff66,  /* Redo, again */
        Menu = 0xff67,
        Find = 0xff68,  /* Find, search */
        Cancel = 0xff69,  /* Cancel, stop, abort, exit */
        Help = 0xff6a,  /* Help */
        Break = 0xff6b,
        Mode_switch = 0xff7e,  /* Character set switch */
        script_switch = 0xff7e,  /* Alias for mode_switch */
        Num_Lock = 0xff7f,

        /* Keypad functions, keypad numbers cleverly chosen to map to ASCII */

        KP_Space = 0xff80,  /* Space */
        KP_Tab = 0xff89,
        KP_Enter = 0xff8d,  /* Enter */
        KP_F1 = 0xff91,  /* PF1, KP_A, ... */
        KP_F2 = 0xff92,
        KP_F3 = 0xff93,
        KP_F4 = 0xff94,
        KP_Home = 0xff95,
        KP_Left = 0xff96,
        KP_Up = 0xff97,
        KP_Right = 0xff98,
        KP_Down = 0xff99,
        KP_Prior = 0xff9a,
        KP_Page_Up = 0xff9a,
        KP_Next = 0xff9b,
        KP_Page_Down = 0xff9b,
        KP_End = 0xff9c,
        KP_Begin = 0xff9d,
        KP_Insert = 0xff9e,
        KP_Delete = 0xff9f,
        KP_Equal = 0xffbd,  /* Equals */
        KP_Multiply = 0xffaa,
        KP_Add = 0xffab,
        KP_Separator = 0xffac,  /* Separator, often comma */
        KP_Subtract = 0xffad,
        KP_Decimal = 0xffae,
        KP_Divide = 0xffaf,

        KP_0 = 0xffb0,
        KP_1 = 0xffb1,
        KP_2 = 0xffb2,
        KP_3 = 0xffb3,
        KP_4 = 0xffb4,
        KP_5 = 0xffb5,
        KP_6 = 0xffb6,
        KP_7 = 0xffb7,
        KP_8 = 0xffb8,
        KP_9 = 0xffb9,

        /*
         * Auxiliary functions; note the duplicate definitions for left and right
         * function keys;  Sun keyboards and a few other manufacturers have such
         * function key groups on the left and/or right sides of the keyboard.
         * We've not found a keyboard with more than 35 function keys total.
         */

        F1 = 0xffbe,
        F2 = 0xffbf,
        F3 = 0xffc0,
        F4 = 0xffc1,
        F5 = 0xffc2,
        F6 = 0xffc3,
        F7 = 0xffc4,
        F8 = 0xffc5,
        F9 = 0xffc6,
        F10 = 0xffc7,
        F11 = 0xffc8,
        L1 = 0xffc8,
        F12 = 0xffc9,
        L2 = 0xffc9,
        F13 = 0xffca,
        L3 = 0xffca,
        F14 = 0xffcb,
        L4 = 0xffcb,
        F15 = 0xffcc,
        L5 = 0xffcc,
        F16 = 0xffcd,
        L6 = 0xffcd,
        F17 = 0xffce,
        L7 = 0xffce,
        F18 = 0xffcf,
        L8 = 0xffcf,
        F19 = 0xffd0,
        L9 = 0xffd0,
        F20 = 0xffd1,
        L10 = 0xffd1,
        F21 = 0xffd2,
        R1 = 0xffd2,
        F22 = 0xffd3,
        R2 = 0xffd3,
        F23 = 0xffd4,
        R3 = 0xffd4,
        F24 = 0xffd5,
        R4 = 0xffd5,
        F25 = 0xffd6,
        R5 = 0xffd6,
        F26 = 0xffd7,
        R6 = 0xffd7,
        F27 = 0xffd8,
        R7 = 0xffd8,
        F28 = 0xffd9,
        R8 = 0xffd9,
        F29 = 0xffda,
        R9 = 0xffda,
        F30 = 0xffdb,
        R10 = 0xffdb,
        F31 = 0xffdc,
        R11 = 0xffdc,
        F32 = 0xffdd,
        R12 = 0xffdd,
        F33 = 0xffde,
        R13 = 0xffde,
        F34 = 0xffdf,
        R14 = 0xffdf,
        F35 = 0xffe0,
        R15 = 0xffe0,

        /* Modifiers */

        Shift_L = 0xffe1,  /* Left shift */
        Shift_R = 0xffe2,  /* Right shift */
        Control_L = 0xffe3,  /* Left control */
        Control_R = 0xffe4,  /* Right control */
        Caps_Lock = 0xffe5,  /* Caps lock */
        Shift_Lock = 0xffe6,  /* Shift lock */

        Meta_L = 0xffe7,  /* Left meta */
        Meta_R = 0xffe8,  /* Right meta */
        Alt_L = 0xffe9,  /* Left alt */
        Alt_R = 0xffea,  /* Right alt */
        Super_L = 0xffeb,  /* Left super */
        Super_R = 0xffec,  /* Right super */
        Hyper_L = 0xffed,  /* Left hyper */
        Hyper_R = 0xffee,  /* Right hyper */

        ISO_Level3_Shift = 0xfe03,

        /*
         * Latin 1
         * (ISO/IEC 8859-1 = Unicode U+0020..U+00FF)
         * Byte 3 = 0
         */

        space = 0x0020,  /* U+0020 SPACE */
        exclam = 0x0021,  /* U+0021 EXCLAMATION MARK */
        quotedbl = 0x0022,  /* U+0022 QUOTATION MARK */
        numbersign = 0x0023,  /* U+0023 NUMBER SIGN */
        dollar = 0x0024,  /* U+0024 DOLLAR SIGN */
        percent = 0x0025,  /* U+0025 PERCENT SIGN */
        ampersand = 0x0026,  /* U+0026 AMPERSAND */
        apostrophe = 0x0027,  /* U+0027 APOSTROPHE */
        quoteright = 0x0027,  /* deprecated */
        parenleft = 0x0028,  /* U+0028 LEFT PARENTHESIS */
        parenright = 0x0029,  /* U+0029 RIGHT PARENTHESIS */
        asterisk = 0x002a,  /* U+002A ASTERISK */
        plus = 0x002b,  /* U+002B PLUS SIGN */
        comma = 0x002c,  /* U+002C COMMA */
        minus = 0x002d,  /* U+002D HYPHEN-MINUS */
        period = 0x002e,  /* U+002E FULL STOP */
        slash = 0x002f,  /* U+002F SOLIDUS */
        Number0 = 0x0030,  /* U+0030 DIGIT ZERO */
        Number1 = 0x0031,  /* U+0031 DIGIT ONE */
        Number2 = 0x0032,  /* U+0032 DIGIT TWO */
        Number3 = 0x0033,  /* U+0033 DIGIT THREE */
        Number4 = 0x0034,  /* U+0034 DIGIT FOUR */
        Number5 = 0x0035,  /* U+0035 DIGIT FIVE */
        Number6 = 0x0036,  /* U+0036 DIGIT SIX */
        Number7 = 0x0037,  /* U+0037 DIGIT SEVEN */
        Number8 = 0x0038,  /* U+0038 DIGIT EIGHT */
        Number9 = 0x0039,  /* U+0039 DIGIT NINE */
        colon = 0x003a,  /* U+003A COLON */
        semicolon = 0x003b,  /* U+003B SEMICOLON */
        less = 0x003c,  /* U+003C LESS-THAN SIGN */
        equal = 0x003d,  /* U+003D EQUALS SIGN */
        greater = 0x003e,  /* U+003E GREATER-THAN SIGN */
        question = 0x003f,  /* U+003F QUESTION MARK */
        at = 0x0040,  /* U+0040 COMMERCIAL AT */
        A = 0x0041,  /* U+0041 LATIN CAPITAL LETTER A */
        B = 0x0042,  /* U+0042 LATIN CAPITAL LETTER B */
        C = 0x0043,  /* U+0043 LATIN CAPITAL LETTER C */
        D = 0x0044,  /* U+0044 LATIN CAPITAL LETTER D */
        E = 0x0045,  /* U+0045 LATIN CAPITAL LETTER E */
        F = 0x0046,  /* U+0046 LATIN CAPITAL LETTER F */
        G = 0x0047,  /* U+0047 LATIN CAPITAL LETTER G */
        H = 0x0048,  /* U+0048 LATIN CAPITAL LETTER H */
        I = 0x0049,  /* U+0049 LATIN CAPITAL LETTER I */
        J = 0x004a,  /* U+004A LATIN CAPITAL LETTER J */
        K = 0x004b,  /* U+004B LATIN CAPITAL LETTER K */
        L = 0x004c,  /* U+004C LATIN CAPITAL LETTER L */
        M = 0x004d,  /* U+004D LATIN CAPITAL LETTER M */
        N = 0x004e,  /* U+004E LATIN CAPITAL LETTER N */
        O = 0x004f,  /* U+004F LATIN CAPITAL LETTER O */
        P = 0x0050,  /* U+0050 LATIN CAPITAL LETTER P */
        Q = 0x0051,  /* U+0051 LATIN CAPITAL LETTER Q */
        R = 0x0052,  /* U+0052 LATIN CAPITAL LETTER R */
        S = 0x0053,  /* U+0053 LATIN CAPITAL LETTER S */
        T = 0x0054,  /* U+0054 LATIN CAPITAL LETTER T */
        U = 0x0055,  /* U+0055 LATIN CAPITAL LETTER U */
        V = 0x0056,  /* U+0056 LATIN CAPITAL LETTER V */
        W = 0x0057,  /* U+0057 LATIN CAPITAL LETTER W */
        X = 0x0058,  /* U+0058 LATIN CAPITAL LETTER X */
        Y = 0x0059,  /* U+0059 LATIN CAPITAL LETTER Y */
        Z = 0x005a,  /* U+005A LATIN CAPITAL LETTER Z */
        bracketleft = 0x005b,  /* U+005B LEFT SQUARE BRACKET */
        backslash = 0x005c,  /* U+005C REVERSE SOLIDUS */
        bracketright = 0x005d,  /* U+005D RIGHT SQUARE BRACKET */
        asciicircum = 0x005e,  /* U+005E CIRCUMFLEX ACCENT */
        underscore = 0x005f,  /* U+005F LOW LINE */
        grave = 0x0060,  /* U+0060 GRAVE ACCENT */
        quoteleft = 0x0060,  /* deprecated */
        a = 0x0061,  /* U+0061 LATIN SMALL LETTER A */
        b = 0x0062,  /* U+0062 LATIN SMALL LETTER B */
        c = 0x0063,  /* U+0063 LATIN SMALL LETTER C */
        d = 0x0064,  /* U+0064 LATIN SMALL LETTER D */
        e = 0x0065,  /* U+0065 LATIN SMALL LETTER E */
        f = 0x0066,  /* U+0066 LATIN SMALL LETTER F */
        g = 0x0067,  /* U+0067 LATIN SMALL LETTER G */
        h = 0x0068,  /* U+0068 LATIN SMALL LETTER H */
        i = 0x0069,  /* U+0069 LATIN SMALL LETTER I */
        j = 0x006a,  /* U+006A LATIN SMALL LETTER J */
        k = 0x006b,  /* U+006B LATIN SMALL LETTER K */
        l = 0x006c,  /* U+006C LATIN SMALL LETTER L */
        m = 0x006d,  /* U+006D LATIN SMALL LETTER M */
        n = 0x006e,  /* U+006E LATIN SMALL LETTER N */
        o = 0x006f,  /* U+006F LATIN SMALL LETTER O */
        p = 0x0070,  /* U+0070 LATIN SMALL LETTER P */
        q = 0x0071,  /* U+0071 LATIN SMALL LETTER Q */
        r = 0x0072,  /* U+0072 LATIN SMALL LETTER R */
        s = 0x0073,  /* U+0073 LATIN SMALL LETTER S */
        t = 0x0074,  /* U+0074 LATIN SMALL LETTER T */
        u = 0x0075,  /* U+0075 LATIN SMALL LETTER U */
        v = 0x0076,  /* U+0076 LATIN SMALL LETTER V */
        w = 0x0077,  /* U+0077 LATIN SMALL LETTER W */
        x = 0x0078,  /* U+0078 LATIN SMALL LETTER X */
        y = 0x0079,  /* U+0079 LATIN SMALL LETTER Y */
        z = 0x007a,  /* U+007A LATIN SMALL LETTER Z */
        braceleft = 0x007b,  /* U+007B LEFT CURLY BRACKET */
        bar = 0x007c,  /* U+007C VERTICAL LINE */
        braceright = 0x007d,  /* U+007D RIGHT CURLY BRACKET */
        asciitilde = 0x007e,  /* U+007E TILDE */

        // Extra keys

        XF86AudioMute = 0x1008ff12,
        XF86AudioLowerVolume = 0x1008ff11,
        XF86AudioRaiseVolume = 0x1008ff13,
        XF86PowerOff = 0x1008ff2a,
        XF86Suspend = 0x1008ffa7,
        XF86Copy = 0x1008ff57,
        XF86Paste = 0x1008ff6d,
        XF86Cut = 0x1008ff58,
        XF86MenuKB = 0x1008ff65,
        XF86Calculator = 0x1008ff1d,
        XF86Sleep = 0x1008ff2f,
        XF86WakeUp = 0x1008ff2b,
        XF86Explorer = 0x1008ff5d,
        XF86Send = 0x1008ff7b,
        XF86Xfer = 0x1008ff8a,
        XF86Launch1 = 0x1008ff41,
        XF86Launch2 = 0x1008ff42,
        XF86Launch3 = 0x1008ff43,
        XF86Launch4 = 0x1008ff44,
        XF86Launch5 = 0x1008ff45,
        XF86LaunchA = 0x1008ff4a,
        XF86LaunchB = 0x1008ff4b,
        XF86WWW = 0x1008ff2e,
        XF86DOS = 0x1008ff5a,
        XF86ScreenSaver = 0x1008ff2d,
        XF86RotateWindows = 0x1008ff74,
        XF86Mail = 0x1008ff19,
        XF86Favorites = 0x1008ff30,
        XF86MyComputer = 0x1008ff33,
        XF86Back = 0x1008ff26,
        XF86Forward = 0x1008ff27,
        XF86Eject = 0x1008ff2c,
        XF86AudioPlay = 0x1008ff14,
        XF86AudioStop = 0x1008ff15,
        XF86AudioPrev = 0x1008ff16,
        XF86AudioNext = 0x1008ff17,
        XF86AudioRecord = 0x1008ff1c,
        XF86AudioPause = 0x1008ff31,
        XF86AudioRewind = 0x1008ff3e,
        XF86AudioForward = 0x1008ff97,
        XF86Phone = 0x1008ff6e,
        XF86Tools = 0x1008ff81,
        XF86HomePage = 0x1008ff18,
        XF86Close = 0x1008ff56,
        XF86Reload = 0x1008ff73,
        XF86ScrollUp = 0x1008ff78,
        XF86ScrollDown = 0x1008ff79,
        XF86New = 0x1008ff68,
        XF86TouchpadToggle = 0x1008ffa9,
        XF86WebCam = 0x1008ff8f,
        XF86Search = 0x1008ff1b,
        XF86Finance = 0x1008ff3c,
        XF86Shop = 0x1008ff36,
        XF86MonBrightnessDown = 0x1008ff03,
        XF86MonBrightnessUp = 0x1008ff02,
        XF86AudioMedia = 0x1008ff32,
        XF86Display = 0x1008ff59,
        XF86KbdLightOnOff = 0x1008ff04,
        XF86KbdBrightnessDown = 0x1008ff06,
        XF86KbdBrightnessUp = 0x1008ff05,
        XF86Reply = 0x1008ff72,
        XF86MailForward = 0x1008ff90,
        XF86Save = 0x1008ff77,
        XF86Documents = 0x1008ff5b,
        XF86Battery = 0x1008ff93,
        XF86Bluetooth = 0x1008ff94,
        XF86WLAN = 0x1008ff95,

        SunProps = 0x1005ff70,
        SunOpen = 0x1005ff73,
    }
}

